package com.example.photo.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.photo.common.BaseResponse;
import com.example.photo.common.ErrorCode;
import com.example.photo.constant.OrderType;
import com.example.photo.constant.WorkStatus;
import com.example.photo.exception.BusinessException;
import com.example.photo.model.VO.ScoreWorkVO;
import com.example.photo.model.VO.WorkVO;
import com.example.photo.model.domain.Prize;
import com.example.photo.model.domain.User;
import com.example.photo.model.domain.Work;
import com.example.photo.model.request.add.NewWorkRequest;
import com.example.photo.model.request.update.UpdateWorkRequest;
import com.example.photo.service.PrizeService;
import com.example.photo.service.UserService;
import com.example.photo.service.WorkService;
import com.example.photo.utils.JwtTokenUtils;
import com.example.photo.utils.ResultUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 作品接口
 *
 * @author Lwh
 * @time 2023/04/07 08:52
 */
@RestController
@RequestMapping("/work")
public class WorkController {

    @Resource
    private WorkService workService;

    @Resource
    private UserService userService;

    @Resource
    private PrizeService prizeService;

    /**
     * 用户上传作品
     *
     * @param newWorkRequest 上传作品信息
     * @return 作品展示信息
     */
    @PostMapping("/new")
    public BaseResponse<WorkVO> newWork(@RequestBody NewWorkRequest newWorkRequest,
                                        HttpServletRequest request) {
        if (newWorkRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Integer userId = Integer.valueOf(request.getHeader(JwtTokenUtils.USERID_HEADER));
        WorkVO workVO = workService.saveWork(newWorkRequest, userId);
        if (workVO == null) {
            throw new BusinessException(ErrorCode.SERVER_ERROR, "作品保存失败");
        }

        return ResultUtils.success(workVO);
    }

    /**
     * 用户查看单个作品：根据id查询作品详细信息（浏览量自增）
     *
     * @param workId 作品id
     * @return 作品信息
     */
    @GetMapping("/detail")
    public BaseResponse<WorkVO> getDetailById(@RequestParam Integer workId) {
        if (workId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Work work = workService.getById(workId);
        if (work == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "查询的作品不存在");
        }
        WorkVO workVO = new WorkVO(work);

        //设置作者头像
        Integer makerId = work.getMakerId();
        if (makerId != null && makerId > 1) {
            User maker = userService.getById(makerId);
            workVO.setMakerAvatar(maker.getAvatar());
            workVO.setMakerName(maker.getNickname());
        }

        //增加浏览量
        new Thread(() -> workService.viewIncrement(work.getWorkId())).start();

        return ResultUtils.success(workVO);
    }

    /**
     * 用户查询自己上传的作品：根据作者id批量查询作品
     *
     * @param makerId 用户id
     * @return 作品列表
     */
    @GetMapping("/list")
    public BaseResponse<List<WorkVO>> getWorksByMakerId(@RequestParam Integer makerId) {
        if (makerId < 1) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        List<WorkVO> works = workService.getWorksByMarkerId(makerId);
        List<WorkVO> workVOList = works.stream().peek(workVO -> workVO.setDescription(""))
                .peek(workVO -> {
                    Integer prizeId = workVO.getPrizeId();
                    if (prizeId != 0) {
                        String prizeName = prizeService.getById(prizeId).getPrizeName();
                        workVO.setPrizeName(StringUtils.isBlank(prizeName) ? "" : prizeName);
                    } else {
                        workVO.setPrizeName("");
                    }
                }).collect(Collectors.toList());
        return ResultUtils.success(workVOList);
    }

    /**
     * 根据赛事id批量查询参赛作品（包含未获奖的），按照浏览量降序排列
     *
     * @param contestId 赛事id
     * @return 作品列表
     */
    @GetMapping("/contest/list")
    public BaseResponse<List<ScoreWorkVO>> getWorksByContestId(@RequestParam long pageSize,
                                                               @RequestParam long pageNum,
                                                               @RequestParam Integer contestId) {
        if (contestId < 1) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        List<ScoreWorkVO> workVOList = getOrderedWorks(pageSize, pageNum, contestId, OrderType.VIEW);
        return ResultUtils.success(workVOList);
    }

    /**
     * 根据赛事id批量查询参赛作品（包含未获奖的），按照id降序排列（近似投稿时间）
     *
     * @param contestId 赛事id
     */
    @GetMapping("/contest/ordered")
    public BaseResponse<List<ScoreWorkVO>> getLatestWorksByContestId(@RequestParam long pageSize,
                                                                     @RequestParam long pageNum,
                                                                     @RequestParam Integer contestId) {
        if (contestId < 1) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        List<ScoreWorkVO> workVOList = getOrderedWorks(pageSize, pageNum, contestId, OrderType.TIME);
        return ResultUtils.success(workVOList);
    }

    /**
     * 传入排序类型，分页查询某个赛事的全部作品（主页展示）
     *
     * @param orderType 1-时间，2-浏览量，3-均分
     */
    private List<ScoreWorkVO> getOrderedWorks(long pageSize, long pageNum, Integer contestId, Integer orderType) {
        String order = "";
        switch (orderType) {
            case OrderType.TIME:
                order = "work_id";
                break;
            case OrderType.VIEW:
                order = "views";
                break;
            case OrderType.SCORE:
                order = "average";
                break;
        }
        QueryWrapper<Work> wrapper = new QueryWrapper<>();
        wrapper.eq("contest_id", contestId);
        wrapper.eq("is_pass", WorkStatus.PASS);
        wrapper.orderByDesc(order);
        //分页查询
        List<Work> works = workService.page(new Page<>(pageNum, pageSize), wrapper).getRecords();
        //结果为空表示当前赛事暂无参赛作品，返回空列表
        if (works.size() == 0) {
            return new ArrayList<>();
        }
        //设置作者昵称头像（考虑作品表应增加字段，否则查库次数有点多）
        return works.stream()
                .map(ScoreWorkVO::new)
                .peek(userWorkVO -> {
                    Integer prizeId = userWorkVO.getPrizeId();
                    Prize prize = prizeService.getById(prizeId);
                    if (prize != null) {
                        userWorkVO.setPrizeName(prize.getPrizeName());
                    }
                    User user = userService.getById(userWorkVO.getMakerId());
                    userWorkVO.setMakerAvatar(user.getAvatar());
                    userWorkVO.setMakerName(user.getNickname());
                })
                .peek(vo -> vo.setDescription(""))
                .collect(Collectors.toList());
    }

    /**
     * 根据赛事id批量查询 已获奖的 作品（按照奖项分类）
     *
     * @param contestId 赛事id
     * @return 以奖项id为键，作品列表为值的map
     */
    @GetMapping("/contest/prized")
    public BaseResponse<Map<Integer, List<ScoreWorkVO>>> getPrizedWorksByContestId(@RequestParam Integer contestId) {
        if (contestId < 1) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        List<ScoreWorkVO> works = workService.getAllWorksByContestId(contestId);

        //当前赛事无参赛作品则直接返回空map
        if (works.size() == 0) {
            return ResultUtils.success(new HashMap<>());
        }

        //只取奖项id大于0的作品
        List<ScoreWorkVO> prizedWorks = works.stream()
                .filter(userWorkVO -> userWorkVO.getPrizeId() > 0)
                .peek(workVO -> {
                    User user = userService.getById(workVO.getMakerId());
                    Integer prizeId = workVO.getPrizeId();
                    Prize prize = prizeService.getById(prizeId);
                    if (prize != null) {
                        workVO.setPrizeName(prize.getPrizeName());
                    }
                    workVO.setDescription("");
                    workVO.setMakerName(user.getNickname());
                    workVO.setMakerAvatar(user.getAvatar());
                })
                .collect(Collectors.toList());

        Map<Integer, List<ScoreWorkVO>> map = new HashMap<>();

        //获取该赛事的所有奖项
        List<Integer> prizeIds = prizeService.getIdsByContestId(contestId);
        for (Integer prizeId : prizeIds) {
            map.put(prizeId, new ArrayList<>());
        }
        //按奖项id将作品分类
        prizedWorks.forEach(work -> {
            Integer prizeId = work.getPrizeId();
            map.get(prizeId).add(work);
        });

        return ResultUtils.success(map);
    }

    /**
     * 根据赛事id批量查询 已审核的 作品
     */
    @Deprecated
//    @GetMapping("/contest/passed")
    public BaseResponse<List<ScoreWorkVO>> getPassedWorksByContestId(@RequestParam Integer contestId) {
        if (contestId < 1) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        List<ScoreWorkVO> works = workService.getAllWorksByContestId(contestId);
        //当前赛事无参赛作品则直接返回空列表
        if (works.size() == 0) {
            return ResultUtils.success(works);
        }
        //只取已通过审核的部分
        return ResultUtils.success(works.stream()
                .filter(userWorkVO -> userWorkVO.getIsPass() == WorkStatus.PASS)
                .peek(workVO -> userService.getById(workVO.getMakerId()))
                .collect(Collectors.toList()));
    }

    /**
     * 用户修改作品信息
     *
     * @param updateWorkRequest 修改后的作品信息
     * @return 修改后的作品信息对象
     */
    @PostMapping("/update")
    public BaseResponse<WorkVO> updateWork(@RequestBody UpdateWorkRequest updateWorkRequest,
                                           HttpServletRequest request) {
        if (updateWorkRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //试图获取旧的作品信息
        Integer workId = updateWorkRequest.getWorkId();
        Work oldWork = workService.getById(workId);
        if (oldWork == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "要修改的作品不存在");
        }

        //判断要修改的作品是否是由当前登录用户上传的
        Integer makerId = oldWork.getMakerId();
        Integer userId = Integer.valueOf(request.getHeader(JwtTokenUtils.USERID_HEADER));
        if (!Objects.equals(makerId, userId)) {
            throw new BusinessException(ErrorCode.NO_AUTH, "无法修改其他用户上传的作品");
        }

        WorkVO workVO = workService.updateWorkInfo(updateWorkRequest);
        if (workVO == null) {
            throw new BusinessException(ErrorCode.SERVER_ERROR, "修改作品信息失败");
        }
        return ResultUtils.success(workVO);
    }

    /**
     * 用户删除自己的作品
     *
     * @param workId 要删除的作品id
     */
    @PostMapping("/remove")
    public BaseResponse<Boolean> removeWorkByUser(@RequestParam Integer workId,
                                                  HttpServletRequest request) {
        if (workId < 1) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //试图获取该作品信息
        Work work = workService.getById(workId);
        if (work == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "要删除的作品不存在");
        }

        //判断要删除的作品是否是由当前登录用户上传的
        if (!Objects.equals(work.getMakerId(), Integer.valueOf(request.getHeader(JwtTokenUtils.USERID_HEADER)))) {
            throw new BusinessException(ErrorCode.NO_AUTH, "不能删除其他用户上传的作品");
        }

        boolean remove = workService.removeById(workId);
        if (!remove) {
            throw new BusinessException(ErrorCode.SERVER_ERROR, "删除作品信息失败");
        }
        return ResultUtils.success(true);
    }

    /**
     * 按组别筛选作品，可选排序方式
     *
     * @param group 组别序号
     * @param order 排序方式
     */
    @GetMapping("/ordered")
    public BaseResponse<List<ScoreWorkVO>> getOrderedWorks(@RequestParam Integer group,
                                                           @RequestParam Integer order,
                                                           @RequestParam Integer pageSize,
                                                           @RequestParam Integer pageNum) {
        if (group == null || order == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        QueryWrapper<Work> wrapper = new QueryWrapper<>();
        wrapper.eq("contest_group", group);
        switch (order) {
            case OrderType.TIME:
                break;
            case OrderType.VIEW:
                wrapper.orderByDesc("views");
                break;
            case OrderType.SCORE:
                wrapper.orderByDesc("average");
                break;
        }
        List<Work> workList = workService.page(new Page<>(pageNum, pageSize), wrapper).getRecords();

        List<ScoreWorkVO> workVOList = workList.stream()
                .map(ScoreWorkVO::new).peek(scoreWorkVO -> {
                    Integer makerId = scoreWorkVO.getMakerId();
                    User maker = userService.getById(makerId);
                    if (maker != null) {
                        scoreWorkVO.setMakerName(maker.getNickname());
                        scoreWorkVO.setMakerAvatar(maker.getAvatar());
                    }

                    Integer prizeId = scoreWorkVO.getPrizeId();
                    Prize prize = prizeService.getById(prizeId);
                    if (prize != null) {
                        scoreWorkVO.setPrizeName(prize.getPrizeName());
                    }
                }).collect(Collectors.toList());

        return ResultUtils.success(workVOList);
    }

}
